#include "req_handle.h"
#include "log_console.h"
#include "custom_handle.h"
#include <cJSON.h>
#include <shmem.h>
#include <msg_queue_peer.h>
#include <file_opt.h>

static struct shm_param para;

//消息队列结构体
struct msgque
{
    long mtype;
    char ctlmsg[256];
};

//共享内存结构体
union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};

#define KB 1024
#define HTML_SIZE (64 * KB)
#define NUM 100

//普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"
#define JSON_HEAD "Content-Type: application/json\r\n" \
                  "Connection: close\r\n"

//cgi回复json请求函数 根据协议格式传入json字符串
static int report_json(const char *msg)
{
    char reply_buf[HTML_SIZE] = {0};
    sprintf(reply_buf, "%sContent-Length: %d\r\n\r\n", JSON_HEAD, strlen(msg));
    strcat(reply_buf, msg);
    //打印回复消息
    log_console("reply:%s", reply_buf);
    fputs(reply_buf, stdout);

    return 0;
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(char *input)
{
    //序列化反序列化变量
    cJSON *root = NULL;
    cJSON *roots = NULL;
    cJSON *item = NULL;
    cJSON *array = NULL;
    cJSON *next = NULL;
    cJSON *sitemk = NULL;
    cJSON *sitemv = NULL;

    roots = cJSON_CreateObject();
    //指向结构体指针
    struct std_node *smp = NULL;

    //指向消息队列
    struct msgque send;

    //int keybuf[8] = {101, 102, 103, 104, 105, 301, 302, 303}; //读取点表获取全部key存放到buf

    char reply_buf[HTML_SIZE] = {0};
    log_console("input:%s", input); //打印网页请求JSON字符串

    //1.初始化共享内存
    int ret = shm_init(&para, "shm_a", sizeof(struct std_node) * NUM + sizeof(int)); //申请共享内存大小
    if (ret < 0)
    {
        return -1;
    }
    int *shm = shm_getaddr(&para); //获取指向共享内存的指针
    if (shm == NULL)
    {
        return -1;
    }
    log_console("shm point:%p\n\n", shm);

    char *p = input; //指针指向input字符串
    //2.判断请求字段是否包含username/password 判断登录信息
    if (strncmp(p, "username", 8) == 0)
    {
        //收到原始消息username=xxx&password=xxx
        //判断用户名和密码 默认用户名&密码都是22071
        while (*p)
        {
            if (*p == '=')
            {
                p++;
                if (strncmp(p, "22071", 5) == 0)
                {
                    continue;
                }
                else
                {
                    return 0;
                }
            }
            else
                p++;
        }
        strcpy(reply_buf, "<script>window.location.href = '/temp_index.html';</script>"); //跳转到主页
        fputs(reply_buf, stdout);
        log_console("login success!\n\n");
    }
    else
    {
        //3.不是登录请求 解析JSON字符串

        log_console("==========else=============\n\n"); //提示语句

        root = cJSON_Parse(input);
        if (!root)
        {
            log_console("ERR:%s", cJSON_GetErrorPtr); //提示错误语句
        }
        else
        {
            item = cJSON_GetObjectItem(root, "type");

            //3.1 type = 4 默认获取全部设备值
            if (item->valueint == 4)
            {
                log_console("get current alldata !!!\n\n"); //提示语句 底层固定时间刷新数据到共享内存 省略发送刷新命令 直接读取共享内存
            }
            else if (item->valueint == 1 || item->valueint == 2) //type =2 控制ModBus终端设备 解析type,key,val
            {
                log_console("control devs !!!\n\n"); //提示语句
                send.mtype = (long)item->valueint;

                sitemk = cJSON_GetObjectItem(root, "key");
                sitemv = cJSON_GetObjectItem(root, "val");

                cJSON_AddNumberToObject(roots, "key", sitemk->valueint);
                cJSON_AddStringToObject(roots, "val", sitemv->valuestring);

                char *str = cJSON_Print(roots);
                log_console("ctlmsg root:%s\n\n", str);
                strcpy(send.ctlmsg, str);

                if (msg_queue_send("msggate", &send, sizeof(struct msgque) * 1, 0) < 0) //确定消息队列主题 发送一个消息队列结构体大小
                {
                    log_console("sendbuf err!");
                }
                log_console("msg control send success!  %s\n\n", str);

                free(str);
                str = NULL;
                cJSON_Delete(roots);
                return 0; //发送完控制数据 结束进程 不需要读取共享内存
            }
            else if (item->valueint == 3) //type = 3 获取点表数据
            {
                log_console("get pointer data !!!\n\n"); //提示语句
                //打开默认路径下.json文件读取
                //先判断文件是否存在
                if (!fileopt_exist("/mnt/config/dev_config.json"))
                {
                    log_console("file %s not exit\n");
                    return -1;
                }

                long size = fileopt_getsize("/mnt/config/dev_config.json");
                char *buf = (char *)malloc(size);

                int ret = fileopt_readall("/mnt/config/dev_config.json", buf);
                if (ret < 0)
                {
                    log_console("read err\n");
                    return -1;
                }
                log_console("read data = \n%s\n", buf);

                //反序列化
                root = cJSON_Parse(buf);
                if (!root)
                {
                    log_console(".json ERR:%s", cJSON_GetErrorPtr); //提示错误语句
                }
                else
                {
                    item = cJSON_GetObjectItem(root, "version");

                    cJSON_AddStringToObject(roots, "val", item->valuestring);

                    char *str = cJSON_Print(roots);
                    log_console("system info root:%s\n\n", str);

                    report_json(str);

                    free(str);
                    str = NULL;
                    cJSON_Delete(roots);
                    free(buf);
                }
            }

            //4.读取共享内存 序列化 按结构体大小 向后移动 根据key值依次读取value值

            //测试
            char *str = "{\"result\": 0,\"data\":[{\"key\":101,\"val\":\"22.5\"},{\"key\":102,\"val\":\"52.5\"},{\"key\": 103,\"val\": 1},{\"key\": 104,\"val\": \"28\"},{\"key\": 303,\"val\": 1}]}";
            log_console("shmroot:%s\n", str); //提示语句
            report_json(str);

            //读共享内存执行代码
            //     root = cJSON_CreateObject();
            //     item = cJSON_CreateObject();
            //     array = cJSON_CreateArray();

            //     cJSON_AddNumberToObject(root, "result", 0);

            //     int n = *shm; //前4字节 后续存放的设备数量
            //     log_console("n:%d", n);
            //     smp = shm + 1; //结构体指针指向共享内存
            //     char temp[32] = {0};
            //     cJSON_AddItemToObject(root, "data", array);

            //     while (n--)
            //     {
            //         log_console("K:%d", smp->key);

            //         next = cJSON_CreateObject();
            //         cJSON_AddItemToArray(array, next);
            //         cJSON_AddNumberToObject(next, "key", smp->key);
            //         if (smp->type == 1)
            //         {
            //             sprintf(temp, "%d", smp->new_val.b_val);
            //             cJSON_AddItemToObject(next, "val", cJSON_CreateString(temp));
            //         }
            //         else if (smp->type == 2)
            //         {
            //             sprintf(temp, "%d", smp->new_val.i_val);
            //             cJSON_AddItemToObject(next, "val", cJSON_CreateString(temp));
            //         }
            //         else if (smp->type == 3)
            //         {
            //             sprintf(temp, "%.2f", smp->new_val.f_val);
            //             cJSON_AddItemToObject(next, "val", cJSON_CreateString(temp));
            //         }
            //         memset(temp, 0, sizeof(temp));
            //         smp++;
            //     }
            //     //5.将JSON字符串输出为char*类型 传入通用cgi回复json请求函数 封装JSON协议头
            //     char *str = cJSON_Print(root);
            //     log_console("shmroot:%s", str);
            //     report_json(str); //传入JSON字符串 数据发送到网页
            //     //删除json产生空间
            //     free(str);
            //     str = NULL;
        }
    }
        log_console("==========parse and process finished!=================\n\n"); //提示语句
        cJSON_Delete(root);
        return 0;
}